package com.lzyc.zbar.camera;

import android.content.Context;
import android.graphics.Point;
import android.hardware.Camera;
import android.view.Display;
import android.view.Surface;
import android.view.WindowManager;

import com.lzyc.ybtappcal.util.ScreenUtils;

import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;

final class CameraConfigurationManager {
  private static final int TEN_DESIRED_ZOOM = 27;
  private static final Pattern COMMA_PATTERN = Pattern.compile(",");
  private final Context mContext;
  private Point mScreenResolution;
  private Point cameraResolution;

  public CameraConfigurationManager(Context context) {
    mContext = context;
  }

  public void initFromCameraParameters(Camera camera) {
    mScreenResolution = new Point(ScreenUtils.getScreenWidth(), ScreenUtils.getScreenHeight());
    Point screenResolutionForCamera = new Point();
    screenResolutionForCamera.x = mScreenResolution.x;
    screenResolutionForCamera.y = mScreenResolution.y;
    if (mScreenResolution.x < mScreenResolution.y) {
      screenResolutionForCamera.x = mScreenResolution.y;
      screenResolutionForCamera.y = mScreenResolution.x;
    }
    cameraResolution = getCameraResolution(camera.getParameters(), screenResolutionForCamera);
  }

  public Point getCameraResolution() {
    return  cameraResolution;
  }

  public void setDesiredCameraParameters(Camera camera) {
    Camera.Parameters parameters = camera.getParameters();
    parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);
    setZoom(parameters);
    camera.setDisplayOrientation(getDisplayOrientation());
    camera.setParameters(parameters);
  }

  public void openFlashlight(Camera camera) {
    doSetTorch(camera, true);
  }

  public void closeFlashlight(Camera camera) {
    doSetTorch(camera, false);
  }

  private void doSetTorch(Camera camera, boolean newSetting) {
    Camera.Parameters parameters = camera.getParameters();
    String flashMode;
    /** 是否支持闪光灯 */
    if (newSetting) {
      flashMode = findSettableValue(parameters.getSupportedFlashModes(), Camera.Parameters.FLASH_MODE_TORCH, Camera.Parameters.FLASH_MODE_ON);
    } else {
      flashMode = findSettableValue(parameters.getSupportedFlashModes(), Camera.Parameters.FLASH_MODE_OFF);
    }
    if (flashMode != null) {
      parameters.setFlashMode(flashMode);
    }
    camera.setParameters(parameters);
  }

  private static String findSettableValue(Collection<String> supportedValues, String... desiredValues) {
    String result = null;
    if (supportedValues != null) {
      for (String desiredValue : desiredValues) {
        if (supportedValues.contains(desiredValue)) {
          result = desiredValue;
          break;
        }
      }
    }
    return result;
  }

  public int getDisplayOrientation() {
    Camera.CameraInfo info = new Camera.CameraInfo();
    Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, info);
    WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();

    int rotation = display.getRotation();
    int degrees = 0;
    switch (rotation) {
      case Surface.ROTATION_0:
        degrees = 0;
        break;
      case Surface.ROTATION_90:
        degrees = 90;
        break;
      case Surface.ROTATION_180:
        degrees = 180;
        break;
      case Surface.ROTATION_270:
        degrees = 270;
        break;
    }
    int result;
    if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
      result = (info.orientation + degrees) % 360;
      result = (360 - result) % 360;
    } else {
      result = (info.orientation - degrees + 360) % 360;
    }
    return result;
  }

  private static Point getCameraResolution(Camera.Parameters parameters, Point screenResolution) {
    Point cameraResolution =
            findBestPreviewSizeValue(parameters.getSupportedPreviewSizes(), screenResolution);
    if (cameraResolution == null) {
      cameraResolution = new Point((screenResolution.x >> 3) << 3, (screenResolution.y >> 3) << 3);
    }
    return cameraResolution;
  }

  private static Point findBestPreviewSizeValue(List<Camera.Size> supportSizeList, Point screenResolution) {
    int bestX = 0;
    int bestY = 0;
    int diff = Integer.MAX_VALUE;
    for (Camera.Size previewSize : supportSizeList) {
      int newX = previewSize.width;
      int newY = previewSize.height;

      int newDiff = Math.abs(newX - screenResolution.x) + Math.abs(newY - screenResolution.y);
      if (newDiff == 0) {
        bestX = newX;
        bestY = newY;
        break;
      } else if (newDiff < diff) {
        bestX = newX;
        bestY = newY;
        diff = newDiff;
      }

    }
    if (bestX > 0 && bestY > 0) {
      return new Point(bestX, bestY);
    }
    return null;
  }

  private static int findBestMotZoomValue(CharSequence stringValues, int tenDesiredZoom) {
    int tenBestValue = 0;
    for (String stringValue : COMMA_PATTERN.split(stringValues)) {
      stringValue = stringValue.trim();
      double value;
      try {
        value = Double.parseDouble(stringValue);
      } catch (NumberFormatException nfe) {
        return tenDesiredZoom;
      }
      int tenValue = (int) (10.0 * value);
      if (Math.abs(tenDesiredZoom - value) < Math.abs(tenDesiredZoom
              - tenBestValue)) {
        tenBestValue = tenValue;
      }
    }
    return tenBestValue;
  }


  private void setZoom(Camera.Parameters parameters) {
    String zoomSupportedString = parameters.get("zoom-supported");
    if (zoomSupportedString != null && !Boolean.parseBoolean(zoomSupportedString)) {
      return;
    }
    int tenDesiredZoom = TEN_DESIRED_ZOOM;
    String maxZoomString = parameters.get("max-zoom");
    if (maxZoomString != null) {
      try {
        int tenMaxZoom = (int) (10.0 * Double.parseDouble(maxZoomString));
        if (tenDesiredZoom > tenMaxZoom) {
          tenDesiredZoom = tenMaxZoom;
        }
      } catch (NumberFormatException nfe) {
      }
    }
    String takingPictureZoomMaxString = parameters.get("taking-picture-zoom-max");
    if (takingPictureZoomMaxString != null) {
      try {
        int tenMaxZoom = Integer.parseInt(takingPictureZoomMaxString);
        if (tenDesiredZoom > tenMaxZoom) {
          tenDesiredZoom = tenMaxZoom;
        }
      } catch (NumberFormatException nfe) {
      }
    }
    String motZoomValuesString = parameters.get("mot-zoom-values");
    if (motZoomValuesString != null) {
      tenDesiredZoom = findBestMotZoomValue(motZoomValuesString, tenDesiredZoom);
    }

    String motZoomStepString = parameters.get("mot-zoom-step");
    if (motZoomStepString != null) {
      try {
        double motZoomStep = Double.parseDouble(motZoomStepString.trim());
        int tenZoomStep = (int) (10.0 * motZoomStep);
        if (tenZoomStep > 1) {
          tenDesiredZoom -= tenDesiredZoom % tenZoomStep;
        }
      } catch (NumberFormatException nfe) {
        // continue
      }
    }
    if (maxZoomString != null || motZoomValuesString != null) {
      parameters.set("zoom", String.valueOf(tenDesiredZoom / 10.0));
    }
    if (takingPictureZoomMaxString != null) {
      parameters.set("taking-picture-zoom", tenDesiredZoom);
    }
  }
  public Point getmScreenResolution() {
    return mScreenResolution;
  }
  public void setmScreenResolution(Point mScreenResolution) {
    this.mScreenResolution = mScreenResolution;
  }
}